package com.zx.crowdfunding.handler;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpSession;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.zx.crowdfunding.api.MySQLRemoteService;
import com.zx.crowdfunding.api.RedisRemoteService;
import com.zx.crowdfunding.config.ShortMessageProperties;
import com.zx.crowdfunding.constant.CrowdFundingConstant;
import com.zx.crowdfunding.entity.po.MemberPO;
import com.zx.crowdfunding.entity.vo.MemberLoginVO;
import com.zx.crowdfunding.entity.vo.MemberVO;
import com.zx.crowdfunding.util.CrowdFundingUtil;
import com.zx.crowdfunding.util.ResultEntity;

/**
 * 会员 - Handler
 * @author 郑雪
 * @date 2021-12-31
 */
@Controller
public class MemberHandler {
	
	/**
	 * 第三方短信接口属性
	 */
	@Autowired
	private ShortMessageProperties shortMessageProperties;
	
	/**
	 * Redis数据服务远程接口
	 */
	@Autowired
	private RedisRemoteService redisRemoteService;
	
	/**
	 * MySQL数据服务远程接口
	 */
	@Autowired
	private MySQLRemoteService mysqlRemoteService;
	
	/**
	 * 会员退出登录
	 * @param session 当前会话
	 * @return 重定向到门户首页
	 */
	@RequestMapping("/auth/member/do/logout")
	public String logout(HttpSession session) {
		
		// 会话失效
		session.invalidate();
		
		// 重定向到门户首页
		return "redirect:/";
	}
	
	/**
	 * 会员登录
	 * @param loginacct 登录账号
	 * @param userpswd 登录密码
	 * @return 重定向到会员中心页面
	 */
	@RequestMapping("/auth/member/do/login")
	public String login(
				@RequestParam("loginacct") String loginacct, 
				@RequestParam("userpswd") String userpswd, 
				ModelMap modelMap, 
				HttpSession session
			) {
		
		// 1.调用远程接口根据登录账号查询MemberPO对象
		ResultEntity<MemberPO> resultEntity = mysqlRemoteService.getMemberPOByLoginAcctRemote(loginacct);
		
		// 如果失败
		if(ResultEntity.FAILED.equals(resultEntity.getResult())) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, resultEntity.getMessage());
			
			return "member-login";
		}
		
		MemberPO memberPO = resultEntity.getData();
		
		if(memberPO == null) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, CrowdFundingConstant.MESSAGE_LOGIN_FAILED);
			
			return "member-login";
		}
		
		// 2.比较密码
		String userpswdDataBase = memberPO.getUserpswd();

		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		
		if(!passwordEncoder.matches(userpswd, userpswdDataBase)) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, CrowdFundingConstant.MESSAGE_LOGIN_FAILED);
			
			return "member-login";
		}
		
		// 3.创建MemberLoginVO对象存入Session域
		MemberLoginVO memberLoginVO = new MemberLoginVO(memberPO.getId(), memberPO.getUsername(), memberPO.getEmail());
		session.setAttribute(CrowdFundingConstant.ATTR_NAME_LOGIN_MEMBER, memberLoginVO);
		
		// 4.重定向到会员中心页面
		return "redirect:/auth/member/to/center/page";
	}
	
	/**
	 * 会员注册
	 * @param memberVO 会员视图对象
	 * @return 重定向到登录页面
	 */
	@RequestMapping("/auth/member/do/register")
	public String saveMember(MemberVO memberVO, ModelMap modelMap){
		
		// 1.获取用户输入的手机号
		String phoneNum = memberVO.getPhoneNum();
		
		// 2.拼接Redis中存储验证码的Key
		String key = CrowdFundingConstant.REDIS_CODE_PREFIX + phoneNum;
		
		// 3.从Redis读取Key对应的Value
		ResultEntity<String> redisResultEntity = redisRemoteService.getRedisStringValueByKeyRemote(key);
		
		// 4.检查查询操作是否有效
		String result = redisResultEntity.getResult();
		if(ResultEntity.FAILED.equals(result)) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, redisResultEntity.getMessage());
			
			return "member-register";
		}
		
		String redisCode = redisResultEntity.getData();
		
		if(redisCode == null) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, CrowdFundingConstant.MESSAGE_CODE_NOT_EXISTS);
			
			return "member-register";
		}
		
		// 5.如果从Redis能够查询到Value，则比较表单验证码和Redis验证码
		String formCode = memberVO.getCode();
		
		if(!Objects.equals(formCode, redisCode)) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, CrowdFundingConstant.MESSAGE_CODE_ERROR);
			
			return "member-register";
		}
		
		// 6.如果验证码一致，则从Redis删除
		redisRemoteService.removeRedisKeyRemote(key);
		
		// 7.执行密码加密
		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		String userpswdBeforeEncode = memberVO.getUserpswd();
		String userpswdAfterEncode = passwordEncoder.encode(userpswdBeforeEncode);
		memberVO.setUserpswd(userpswdAfterEncode);
		
		// 8.执行保存
		// ①创建空的MemberPO对象
		MemberPO memberPO = new MemberPO();
		
		// ②复制属性
		BeanUtils.copyProperties(memberVO, memberPO);
		
		// ③调用远程接口添加会员
		ResultEntity<String> saveResultEntity = mysqlRemoteService.saveMemberRemote(memberPO);
				
		if(ResultEntity.FAILED.equals(saveResultEntity.getResult())) {
			
			modelMap.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, saveResultEntity.getMessage());
			
			return "member-register";
		}
		
		// 9.重定向到登录页面
		return "redirect:/auth/member/to/login/page";
	}

	/**
	 * 发送短信验证码
	 * @param phoneNum 接收短信的手机号
	 * @return JSON数据
	 */
	@RequestMapping("/auth/member/send/short/message.json")
	@ResponseBody
	public ResultEntity<String> sendShortMessage(@RequestParam("phoneNum") String phoneNum){
		
		// 1.发送短信验证码
		ResultEntity<String> sendMessageResultEntity = CrowdFundingUtil.sendCodeByShortMessage(
				shortMessageProperties.getHost(), 
				shortMessageProperties.getPath(), 
				shortMessageProperties.getMethod(), 
				phoneNum, 
				shortMessageProperties.getAppCode(), 
				shortMessageProperties.getSign(), 
				shortMessageProperties.getSkin());
		
		// 2.判断短信发送结果
		if(ResultEntity.SUCCESS.equals(sendMessageResultEntity.getResult())) {
			
			// 3.如果发送成功，则将验证码存入Redis
			// ①从上一步操作的结果中获取随机生成的验证码
			String code = sendMessageResultEntity.getData();
			
			// ②拼接一个用于在Redis中存储数据的key
			String key = CrowdFundingConstant.REDIS_CODE_PREFIX + phoneNum;
			
			// ③调用远程接口存入Redis
			ResultEntity<String> saveRedisResultEntity = redisRemoteService.setRedisKeyValueRemoteWithTimeout(key, code, 5, TimeUnit.MINUTES);
		
			// ④判断结果
			if(ResultEntity.SUCCESS.equals(saveRedisResultEntity.getResult())) {
				
				// 返回成功
				return ResultEntity.successWithoutData();
				
			} else {
				// 返回保存Redis失败
				return saveRedisResultEntity;
			}
		
		} else {
			// 返回发送短信验证码失败
			return sendMessageResultEntity;
		}
		
	}
}
